// On Windows we utilize wintab32.dll to support tablet devices.
// Please refer to the Windtab interface specification 1.1
// from LCS/Telegraphics http://www.pointing.com

// TODO Tablet function keys support

using System;
using System.Runtime.InteropServices;

namespace TagTool.Devices.Tablet
{
    /// <summary> Message definitions. Check for in WndProc </summary>
    public enum WTMessage
    {
        Packet = 0x7FF0,
        ContextOpen = 0x7FF0 + 1,
        ContextClose = 0x7FF0 + 2,
        ContextUpdate = 0x7FF0 + 3,
        ContextOverlap = 0x7FF0 + 4,
        Proximity = 0x7FF0 + 5,
        InfoChange = 0x7FF0 + 6,
        CursorChange = 0x7FF0 + 7
    }

    /// <summary> Information categories </summary>
    /// <remarks>
    /// Information on a specific category can be requested through WTInfo()
    /// passing to it a category and an accompaning bit.
    /// </remarks>
    internal enum WTInfoCategory
    {
        Interface = 1,
        Status = 2,
        DefContext = 3,
        DefSysContext = 4,
        DDCTXS = 400,
        DSCTXS = 500,
        Devices = 100,
        Cursors = 200,
        Extensions = 300,
    }

    /// <summary> Interface bits </summary>
    /// <remarks> Use WTInfo() to address specific interface information </remarks>
    internal enum WTInterface
    {
        WintabId = 1,
        SpecVersion = 2,
        ImplVersion = 3,
        NDevices = 4,
        NCursors = 5,
        NContexts = 6,
        ContexctOptions = 7,
        ContextSaveSize = 8,
        NExtensions = 9,
        NManagers = 10
    }

    /// <summary> Status bits </summary>
    /// <remarks> Use WTInfo() to address specific status information </remarks>
    internal enum WTStatus
    {
        Contexts = 1,
        SystemContexts = 2,
        PacketRate = 3,
        PacketData = 4,
        Managers = 5,
        System = 6,
        ButtonUse = 7,
        SystemButtonUse = 8,
        Maximum = 8
    }

    /// <summary> Packet Bits </summary>
    /// <remarks>
    /// Define the packet structure by joining these bits with 'OR'
    /// into the field PacketData of a context.
    /// </remarks>
    internal enum WTPkt
    {
        Context = 0x0001,	/* reporting context */
        Status = 0x0002,	/* status bits */
        Time = 0x0004,	/* time stamp */
        Changed = 0x0008,	/* change bit vector */
        SerialNumber = 0x0010,	/* packet serial number */
        Cursor = 0x0020,	/* reporting cursor */
        Buttons = 0x0040, 	/* button information */
        X = 0x0080,	/* x axis */
        Y = 0x0100,	/* y axis */
        Z = 0x0200,	/* z axis */
        NormalPressure = 0x0400,	/* normal or tip pressure */
        TangentPressure = 0x0800,	/* tangential or barrel pressure */
        Orientation = 0x1000,	/* orientation info: tilts */
        Rotation = 0x2000	/* rotation info; 1.1 */
    }

    /// WTInterface device bits
    internal enum WTIDevices
    {
        Name = 1,
        Hardware = 2,
        NCursorTypes = 3,
        FirstCursor = 4,
        PacketRate = 5,
        PacketData = 6,
        PacketMode = 7,
        CursorData = 8,
        XMargin = 9,
        YMargin = 10,
        ZMargin = 11,
        X = 12,
        Y = 13,
        Z = 14,
        NormalPressure = 15,
        TangentPressure = 16,
        Orientation = 17,
        Rotation = 18, /* 1.1 */
        PlugAndPlayId = 19, /* 1.1 */
    }

    /// <summary> Represents a logical context </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct WTContext
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
        public string Name; /* TCHAR */
        public uint Options;
        public uint Status;
        public uint Locks;
        public uint MsgBase;
        public uint Device;
        public uint PktRate;
        public uint PktData;  /* WTPKT = DWORD */
        public uint PktMode;  /* WTPKT = DWORD */
        public uint MoveMask; /* WTPKT = DWORD */
        public uint BtnDnMask; /* DWORD */
        public uint BtnUpMask; /* DWORD */
        public uint InOrgX;
        public uint InOrgY;
        public uint InOrgZ;
        public uint InExtX;
        public uint InExtY;
        public uint InExtZ;
        public uint OutOrgX;
        public uint OutOrgY;
        public uint OutOrgZ;
        public uint OutExtX;
        public uint OutExtY;
        public uint OutExtZ;
        public uint SensX;    /* FIX32 = DWORD */
        public uint SensY;    /* FIX32 = DWORD */
        public uint SensZ;    /* FIX32 = DWORD */
        public bool SysMode;
        public int SysOrgX;
        public int SysOrgY;
        public int SysExtX;
        public int SysExtY;
        public uint SysSensX; /* FIX32 = DWORD */
        public uint SysSensY; /* FIX32 = DWORD  */
    }

    internal enum WTContextOptions
    {
        System = 0x0001,
        Pen = 0x0002,
        Messages = 0x0004,
        Margin = 0x8000,
        MarginInside = 0x4000,
        CursorMessages = 0x0008 /* 1.1 */
    }

    internal enum WTContextStatus
    {
        Disabled = 0x0001,
        Obscured = 0x0002,
        OnTop = 0x0004
    }

    internal enum WTContextLock
    {
        InSize = 0x0001,
        InAspect = 0x0002,
        Sensitivity = 0x0004,
        Margin = 0x0008,
        SystemOut = 0x0010
    }

    /// <summary> Represents a packet </summary>
    [StructLayout(LayoutKind.Sequential)]
    internal struct Packet
    {
        public IntPtr Context;
        public uint Status;
        public int Time;
        public uint Changed;
        public uint SerialNumber;
        public uint Cursor;
        public uint Button;
        public uint X;
        public uint Y;
        public uint Z;
        public uint NormalPressure;
        public uint TangentPressure;
        public WTOrientation Orientation;
        public WTRotation Rotation;
    }

    /// <summary> Packet status definition </summary>
    internal enum WTPacketStatus
    {
        Proximity = 0x0001,
        QueueError = 0x0002,
        Margin = 0x0004,
        Grab = 0x0008,
        Invert = 0x0010 /* 1.1 */
    }

    /// <summary> Represents an axis </summary>
    [StructLayout(LayoutKind.Sequential)]
    internal struct WTAxis
    {
        public int Minimum;
        public int Maximum;
        public uint Units;
        public uint Resolution;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct WTOrientation
    {
        public int Azimuth;
        public int Altitude;
        public int Twist;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct WTRotation
    {
        public int Roll;
        public int Pitch;
        public int Yaw;
    }

    /// <summary> Provides static acces to wintab functions (spec. v1.1) </summary>
    internal static class WTFunction
    {
        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTInfo", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern uint WTInfoUInt(uint wCategory, uint nIndex, ref uint lpOutput);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTInfo", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern uint WTInfoInt(uint wCategory, uint nIndex, ref int lpOutput);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTInfo", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern uint WTInfoAxis(uint wCategory, uint nIndex, ref WTAxis lpOutput);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTInfo", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern uint WTInfoIntPtr(uint wCategory, uint nIndex, ref IntPtr lpOutput);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTInfo", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern uint WTInfoString(uint wCategory, uint nIndex, ref String lpOutput);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTInfo", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern uint WTInfo(uint wCategory, uint nIndex, ref WTContext lpOutput);


        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTOpen", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern IntPtr WTOpen(IntPtr hWnd, ref WTContext lpLogCtx, bool fEnable);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTClose", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTClose(IntPtr hCtx);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTPacketsGet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern int WTPacketsGet(IntPtr hCtx, int cMaxPkts, ref IntPtr lpPkts);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTPacket", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTPacket(IntPtr hCtx, uint wSerial, ref Packet lpPkt);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTEnable", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTEnable(IntPtr hCtx, bool fEnable);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTOverlap", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTOverlap(IntPtr hCtx, bool fToTop);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTConfig", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTConfig(IntPtr hCtx, IntPtr hWnd);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTGet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTGet(IntPtr hCtx, ref WTContext lpLogCtx);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTSet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTSet(IntPtr hCtx, ref WTContext lpLogCtx);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTExtGet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTExtGet(IntPtr hCtx, uint wExt, IntPtr lpData);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTExtSet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTExtSet(IntPtr hCtx, uint wExt, IntPtr lpData);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTSave", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTSave(IntPtr hCtx, IntPtr lpSaveInfo);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTRestore", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern IntPtr WTRestore(IntPtr hCtx, IntPtr lpSaveInfo, bool fEnable);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTPacketsPeek", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern int WTPacketsPeek(IntPtr hCtx, int cMaxPkts, IntPtr lpPkts);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTDataGet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern int WTDataGet(IntPtr hCtx, uint wBegin, uint wEnd, int cMaxPkts, IntPtr lpPkts, IntPtr lpNPkts);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTDataPeek", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern int WTDataPeek(IntPtr hCtx, uint wBegin, uint wEnd, int cMaxPkts, IntPtr lpPkts, IntPtr lpNPkts);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTQueuePacketsEx", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTQueuePacketsEx(IntPtr hCtx, IntPtr lpOld, IntPtr lpNew);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTQueueSizeGet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern int WTQueueSizeGet(IntPtr hCtx);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTQueueSizeGet", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern int WTQueueSizeSet(IntPtr hCtx, int nPkts);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTMgrOpen", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern IntPtr WTMgrOpen(IntPtr hWnd, uint wMsgBase);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTMgrClose", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTMgrClose(IntPtr hMgr);

        [DllImport("wintab32.dll", CharSet = CharSet.Ansi, EntryPoint = "WTMgrContextEnum", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public static extern bool WTMgrContextEnum(IntPtr hMgr, IntPtr lpEnumFunc, IntPtr lParam);

        //[DllImport("tabletDLL.dll", CharSet = CharSet.Unicode, EntryPoint = "?WTGetPosition@@YAHHHAAIAAH111@Z", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        //public static extern bool WTGetPosition(IntPtr lParam, Int32 serial, ref uint btn, ref int x, ref int y, ref int z, ref int pressure);
    }
}
